home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d13
/
pcrsep89.arc
/
CA.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-03-21
|
22KB
|
757 lines
comment |
Library routines for cellular automoton programs.
These routines can be used with programs written
in assembly language, Quick Basic, or C.
Save as CA.ASM
Compile: MASM CA;
or: TASM CA (ignore Location Counter Overflow warning)
|
; Include the next 2 lines if you use Turbo Assembler:
; MASM51
; QUIRKS
EXTRN CaCell:FAR
.Model Medium,Pascal ;Required for Quick Basic
.Data
Modetype struc ;Default values for each mode
mcols dw ? ;Columns in the univers
mrows dw ? ;Rows in the universe
mvidseg dw ? ;Segment of video buffer
mclear dw ? ;Pointer to vid clear routine
mdisp dw ? ;Pointer to display routine
mbufclr dw ? ;Pointer to buffer clear routine
mvoffset dw ? ;Allignment value for text buffers
mdotrep dw ? ;Dot duplications per cell |graphics
mrowrep dw ? ;Row duplications per cell |only
mchar db ? ;Default display character
mcolor db ? ;Default display color
mborder db ? ;Default border value
mvmode db ? ;Video mode to use
Modetype ends
; Mode 1 alters characters for monochrome adapter
mode1 Modetype <80,25, \
0b000h, \
offset txt_disp_clear,\
offset txt_disp_buf, \
offset txt_buf_clear, \
0,0,0, \
' ', 07h, ' ', 7 >
; Mode 2 alters display attributes for monochrome adapter
mode2 Modetype <80,25, \
0b000h, \
offset txt_disp_clear,\
offset txt_disp_buf, \
offset clr_buf_clear, \
1,0,0, \
' ', 07h, ' ', 7 >
; Mode 3 alters display characters in CGA text mode
mode3 Modetype <80,25, \
0b800h, \
offset txt_disp_clear,\
offset txt_disp_buf, \
offset txt_buf_clear, \
0,0,0, \
' ', 07h, ' ', 3 >
; Mode 4 alters display colors in CGA text mode
mode4 Modetype <80,25, \
0b800h, \
offset txt_disp_clear,\
offset txt_disp_buf, \
offset clr_buf_clear, \
1,0,0, \
' ', 07h, ' ', 3 >
; Mode 5 uses CGA 4-color graphics (320x200 Medium resolution)
mode5 modetype <320,199, \
0b800h, \
offset CGA_disp_clear,\
offset CGA_disp_buf, \
offset clr_buf_clear, \
0,1,1, \
0, 0, 0, 4 >
; Mode 6 uses EGA/VGA 16-color graphics
mode6 modetype <320,175, \
0a000h, \
offset EGA_disp_clear,\
offset EGA_disp_buf, \
offset clr_buf_clear, \
0,2,2, \
0, 0, 0, 10h >
maxmode equ 6
modetbl dw mode1, mode2, mode3, mode4, mode5, mode6
rows dw ?
cols dw ?
vidseg dw ?
clear_val equ this word
clear_char db ?
clear_color db ?
border_on dw 1 ;0 = off, 1 = on
row_repeat dw ?
dot_repeat dw ?
voffset dw ? ;0 = chars, 1 = colors
border_val db ?
EVEN
bufcols dw ? ;Columns in buffer
bufsize dw ? ;Total buffer size
bufaddr equ this dword
bufstart dw 0000h
bufseg dw seg ca_buf
cell_array dw ? ;Offset of cell info array
disp_clear_addr dw ?
disp_buf_addr dw ?
buf_clear_addr dw ?
original_mode dw ? ;Original video mode
;ca_buf segment ;64K universe buffer
; dw 8000h dup (?)
;ca_buf ends
.code
;************
; CaInit -- initializes the CA universe and video adapter.
; Call: CaInit (Mode_number, Array_address_offset)
; Returns: 1 = succes, 0 = failure
;************
Public CaInit
CaInit proc far mode_num,array_ptr
test original_mode,-1 ;Mode already changed?
jnz @F ;Yes -- go
mov ah,0fh ;Else read video mode
int 10h ;Call BIOS
sub ah,ah ;Ready to restore mode
mov [original_mode],ax ;Save original mode
@@: mov ax,0 ;Ready to report failure
mov bx,mode_num ;Get requested mode
or bx,bx ;Is mode > 0 ?
jz CaInit_out ;Leave if mode_num = 0
cmp bx,maxmode ;Mode in range?
ja CaInit_out ;No -- leave
dec bx ;Else BX = mode - 1
add bx,bx ;BX = (mode - 1) * 2
mov bx,[modetbl + bx] ;BX = addr. of mode structure
; Now get info about this mode
mov ax,[bx].mrows ;Number of rows
mov rows,ax
mov ax,[bx].mcols ;Number of columns
mov cols,ax
mov ax,[bx].mvidseg ;Video buffer segment addr.
mov vidseg,ax
mov ax,[bx].mclear ;Video clear routine
mov disp_clear_addr,ax
mov ax,[bx].mdisp ;Video display routine
mov disp_buf_addr,ax
mov ax,[bx].mbufclr ;Buffer clear routine
mov buf_clear_addr,ax
mov ax,[bx].mvoffset ;Color/Char. selector
mov voffset,ax
mov ax,[bx].mrowrep ;Graphics row dupl. count
mov row_repeat,ax
mov ax,[bx].mdotrep ;Graphics dot dupl. count
mov dot_repeat,ax
mov al,[bx].mchar ;Default display character
mov clear_char,al
mov al,[bx].mcolor ;Display display color
mov clear_color,al
mov al,[bx].mborder ;Border value
mov border_val,al
mov ax,1 ;Turn borders on
mov border_on,ax
mov ax,array_ptr ;Get array address
mov cell_array,ax
sub ah,ah ;AH=0: Set video mode
mov al,[bx].mvmode ;Get new mode
int 10h ;Set & clear screen
call calc_buf_size ;Calculate buffer stats.
call clear_buf ;Initialize buffer
mov ax,1 ;Show success
CaInit_out: ret
CaInit endp
;************
; CaReset -- Restores original video mode
; Call: CaReset
; Return: None
;************
Public CaReset
CaReset proc far
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
mov ax,original_mode ;Get original video mode
int 10h ;BIOS: Set mode
sub ax,ax ;AX = 0
mov original_mode,ax ;Show no mode set
@@: ret
CaReset endp
;************
; CaWrap turns on or off side-to-side wrap around of the universe
; Call: CaWrap (num) If Num = 0, wrap is turned off (the default)
; else wrap is turned on
; Return: none
;************
Public CaWrap
CaWrap proc far val
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
cmp word ptr [val],1 ;Is val <> 0 ?
sbb ax,ax ;AX = -1 or 0
inc ax ;AX = 0 or 1
mov border_on,ax ;Save value
call calc_buf_size ;Make new buffer stats
call clear_buf ;Clear the buffer
call [disp_clear_addr] ; and the display
@@: ret
CaWrap endp
;************
; CaBorder -- Set new value for the borders or edges of universe
; Call: CaBorder (new_border_value)
; Return: none
;************
Public CaBorder
CaBorder proc far val
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
mov ax,val ;Get new value
mov border_val,al ; and save it
call clear_buf ;Clear the buffer
call [disp_clear_addr] ; and the display
@@: ret
CaBorder endp
;************
; CaChar -- Set new default display character for text modes
; Call: CaChar (new_char_value)
; Return: none
;************
Public CaChar
CaChar proc far val
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
mov ax,val ;Get new value
mov [clear_char],al ;Save just the character
call clear_buf ;Clear the buffer
call [disp_clear_addr] ; and the display
@@: ret
CaChar endp
;************
; CaColor -- Set new default display color
; Call: CaColor (new_color_value)
; Return: none
;************
Public CaColor
CaColor proc far val
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
mov ax,val ;Get new value
mov [clear_color],al ;Save just the color
call clear_buf ;Clear the buffer
call [disp_clear_addr] ; and the display
@@: ret
CaColor endp
;************
; CaClear -- Clear the buffer and the display
; Call: CaClear
; Return: none
;************
Public CaClear
CaClear proc far
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
call clear_buf ;Clear the buffer
call [disp_clear_addr] ; and the display
@@: ret
CaClear endp
;************
; CaSize -- Set row, column, row-repeat, and dot-repeat values
; Only has an effect in CGA and EGA graphics modes
; Call: CaRows (rows_shown, cols_shown, row_repeat, dot_repeat)
; Return: none
;************
Public CaSize
CaSize proc far rows_shown, cols_shown, row_rpt, dot_rpt
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
mov ax,rows_shown ;Get # of rows
mov rows,ax ;And save it
mov ax,cols_shown ;Same for # of columns
mov cols,ax
mov ax,row_rpt ;Row-repeat value
mov row_repeat,ax
mov ax,dot_rpt ;And dot-repeat value
mov dot_repeat,ax
call calc_buf_size ;Recalculate buffer params.
call clear_buf ;Clear the buffer
call [disp_clear_addr] ; and the display
@@: ret
CaSize endp
;************
; CaSet -- Set one cell in the buffer to a specific value
; Call: CaSet (row, column, value)
; Return: none
;************
Public CaSet
CaSet proc far uses di es, row, col, val
les di,bufaddr ;ES:DI ==> universe buffer
test border_on,-1 ;Borders turned on?
jnz @F ;Yes -- go
dec col ;Else make column 0-based
@@: mov ax,row ;Get row number
mul [bufcols] ; Row * cols_per_row
add ax,col ;Offset into buffer
mov bx,ax ;BX has offset
mov ax,val ;Get value
mov es:[di+bx],al ;Store new value
ret
CaSet endp
;************
; CaShow -- Display current contents of universe buffer
; Call: CaShow
; Return: none
;************
Public CaShow
CaShow proc far
test original_mode,-1 ;Has a mode been set?
jz @F ;No -- just leave
call [disp_buf_addr] ;Call correct routine
@@: ret
CaShow endp
;************
; CaGen -- Create a new generation of the universe and display it
; Call: CaGen
; Return: none
; Calls user's CaCell routine for each cell in the universe
;************
Public CaGen
CaGen proc far uses di si es
test original_mode,-1 ;Has a mode been set?
jnz @F ;Yes -- get to work
jmp CaGen_out ;Else just leave
@@: les si,bufaddr ;ES:SI ==> universe buffer
mov di,bufsize ;DI = bytes in use
add di,si ;ES:DI ==> buffer free space
mov cx,bufcols ;CX = columns in buffer
@@: mov al,es:[si] ;Get byte of border
inc si ;Point to next
stosb ;Store in next generation
loop @B ;Do whole border
mov cx,1 ;CX counts rows
CaGen_1: test border_on,-1 ;Side borders turned on?
jz @F ;No -- jump forward
mov al,es:[si] ;Else get border byte
inc si ;Point to first cell
stosb ;Store in next generation
@@: mov dx,1 ;DX counts columns
CaGen_2: push di ;Save pointer
mov di,cell_array ;DS:DI ==> user's data array
mov [di+18],cx ;Save row number
mov [di+20],dx ; and column number
push cx ;Save counters
push dx
sub ah,ah ;AH = 0 always
mov bx,bufcols ;BX = columns in buffer
neg bx ;BX = -BX
mov al,es:[si+bx-1] ;Get NW neighbor
mov [di],ax ;Save it
add di,2 ;Point to next array item
mov al,es:[si+bx] ;Get North neighbor
mov [di],ax
add di,2
mov al,es:[si+bx+1] ;Get NE neighbor
mov [di],ax
add di,2
mov al,es:[si-1] ;Get West neighbor
mov [di],ax
add di,2
mov al,es:[si] ;Get current cell
mov [di],ax
add di,2
mov al,es:[si+1] ;Get East neighbor
mov [di],ax
add di,2
neg bx ;BX = bufcols
mov al,es:[si+bx-1] ;Get SW neighbor
mov [di],ax
add di,2
mov al,es:[si+bx] ;Get South neighbor
mov [di],ax
add di,2
mov al,es:[si+bx+1] ;Get SE neighbor
mov [di],ax
call CaCell ;Let user calculate new value
pop dx ;Recover registers
pop cx
pop di
stosb ;Store new value
inc si ;Point to next cell
inc dx ;Move to next column
cmp dx,cols ;Done with this row?
jle CaGen_2 ;No -- go do another
test border_on,-1 ;Ready for right border
jz @F ;Go if no border
mov al,es:[si] ;Else get border value
inc si ;Point to next position
stosb ;Save in next generation
@@: inc cx ;One row done
cmp cx,rows ;Are they all done?
jg @F ;Yes -- do bottom border
jmp CaGen_1 ;Else do another row
@@: mov cx,[bufcols] ;Else get columns in CX
@@: mov al,es:[si] ;Get border value
inc si ;Point to next
stosb ;Save that value
loop @B ;And do the rest
mov ax,bufsize ;Get bytes in universe
add bufstart,ax ;Set new beginning addr.
call [disp_buf_addr] ;Show this buffer
CaGen_out: ret
CaGen endp
;************
; Internal Routines -- all of the following routines are for
; internal use only and are NOT available to the user
;
; calc_buf_size: calculates and stores number of columns per row in
; the buffer (bufcols) and the total size of the
; buffer (bufsize)
;************
calc_buf_size proc near
mov bx,border_on ;Get border count
add bx,bx ;Doubled for both sides
add bx,cols ;Add display columns
mov [bufcols],bx ;Save total
mov ax,rows ;AX = display rows
add ax,2 ;Add top & bottom border
mul bx ;bufsize = AX * BX
mov bufsize,ax ;Save value
ret
calc_buf_size endp
;************
; clear_buf -- sets the buffer to its clear (default) values
;************
clear_buf proc near uses di es
mov es,bufseg ;ES ==> buffer
sub di,di ;ES:DI ==> start of buffer
jmp [buf_clear_addr] ;Select correct routine
txt_buf_clear: ;For text:
mov al,clear_char ; Get character to use
jmp short @F ; and go to work
clr_buf_clear: ;For color
mov al,clear_color ; Get color to use
@@: mov ah,al ;Duplicate value
mov cx,8000h ;Words in buffer
rep stosw ;Clear entire buffer
sub di,di ;ES:DI ==> beginning again
mov cx,bufcols ;CX = bytes in a column
mov al,border_val ;AL = value for border
rep stosb ;Make top border
test border_on,-1 ;Are side borders needed?
jz clear_buf_1 ;No -- go
mov cx,rows ;Else CX = display rows
mov bx,cols ; BX = display columns
@@: stosb ;Store left border
add di,bx ;Move to right border
stosb ;Store right border
loop @B ;Do all rows
clear_buf_1: mov di,bufsize ;DI ==> past end of buffer
sub di,bufcols ;DI ==> bottom border
mov cx,bufcols ;CX = columns in border
rep stosb ;Make bottom border
sub ax,ax ;AX = 0
mov bufstart,ax ;New starting offset
ret
clear_buf endp
;************
; txt_disp_clear -- Clear the monochrome or CGA text display screen
;************
txt_disp_clear proc near uses di es
mov es,[vidseg] ;ES==> video buffer
mov ax,[rows] ;AX = rows on screen
mul [cols] ;AX = positions on screen
mov cx,ax ;CX = screen positions
mov ax,clear_val ;AX = char & color for clear
sub di,di ;ES:DI==> start of screen
rep stosw ;Fill the screen
ret
txt_disp_clear endp
;************
; CGA_disp_clear -- Clear the CGA 4-color graphics screen
;************
CGA_disp_clear proc near uses di es
mov es,[vidseg] ;ES==> video buffer
mov al,clear_color ;Color in AL
and al,03h ;Use only 2 bits
mov cl,2 ;To shift 2 bits at a time
mov ah,al ;Color in AH: xxxx xxCC
shl al,cl ;Move color to bits 2 & 3
or ah,al ;Color in AH: xxxx CCCC
shl al,cl ;Move color to bits 4 & 5
or ah,al ;Color in AH: xxCC CCCC
shl al,cl ;Move color to bits 6 & 7
or ah,al ;Color in AH: CCCC CCCC
mov al,ah ;Color in AH & AL
mov cx,2000h ;Size of video buffer
sub di,di ;ES:DI ==> start of video
rep stosw ;Fill video buffer
ret
CGA_disp_clear endp
;************
; EGA_disp_clear -- clear the EGA graphics display (mode 10h)
;************
EGA_disp_clear proc near uses di es
mov es,[vidseg]
sub di,di ;ES:DI ==> start of video
mov dx,3ceh ;EGA Graph. controller port
mov ah,clear_color ;Color in AH
sub al,al ;AL = 0 = Set/Reset register
out dx,al ;Put color in Set/Reset reg.
mov ax,0f01h ;Enable Set/Reset reg.
out dx,ax ; for all planes
mov cx,40 * 350 ;Words to clear
rep stosw ;Clear display
mov ax,0001 ;Disable Set/Reset reg.
out dx,ax ; for all planes
ret
EGA_disp_clear endp
;************
; txt_disp_buf -- display the universe in text-based modes (CGA, MDA or EGA)
;************
txt_disp_buf proc near uses di si ds es
local lbrdr_on
mov ax,border_on ;Copy border flag
mov lbrdr_on,ax ; to SS seg
mov es,[vidseg]
sub di,di ;ES:DI ==> video buffer
add di,voffset ;Adjust for text/attributes
mov cx,rows ;CX will count rows
mov dx,cols ;DX counts columns
mov bx,bufcols ;BX = columns in buffer
lds si,bufaddr ;DS:SI ==> universe buffer
add si,bx ;DS:SI ==> 1st row past border
txt_disp_1: push cx ;Save row count
mov cx,dx ;Column count in cx
add si,lbrdr_on ;Skip left border
push di ;Save vid buffer addr.
@@: lodsb ;Read and show
stosb ; one cell (color or char
inc di ; only) and ready for next
loop @B
add si,lbrdr_on ;Skip right border
pop di ;Get back to row beginning
add di,160 ;Spaces in a row
pop cx ;Get row counter
loop txt_disp_1 ;Do for all rows
ret
txt_disp_buf endp
;************
; CGA_disp_buf -- Displays the universe using CGA 4-color, 320x200 graphics
;************
CGA_disp_buf proc near uses di si ds es
local lrow_rpt, ldot_rpt, lbufcols
local lcols, lrows, lend_col, lendcol_flag
mov bx,border_on ;Get border flag
mov ax,row_repeat ;Copy values so we
mov lrow_rpt,ax ; can get to them
mov ax,dot_repeat ; through SS instead
mov ldot_rpt,ax ; of DS
mov ax,bufcols
mov lbufcols,ax
mov ax,cols
mov lcols,ax
mov ax,rows
mov lrows,ax
mov es,[vidseg]
sub di,di ;ES:DI ==> video buffer
lds si,bufaddr ;DS:SI ==> universe buffer
add si,lbufcols ;Skip top border
add si,bx ; and left border
CGA_disp_1: push si ;Save buffer pointers
push di
mov ax,si ;Get start column
add ax,lcols ;AX = last col in row + 1
mov lend_col,ax ;Save the value
sub ax,ax ;AX = 0
mov lendcol_flag,ax ;Turn the flag off
mov bx,ldot_rpt ;BX counts dot repeats
CGA_disp_2: mov cx,4 ;4 dots per graphics byte
sub ax,ax ;Clear accumulator
CGA_disp_3: mov al,[si] ;Get byte
and al,03h ;Keep 2 bits
shl ah,1 ;Move over old value
shl ah,1 ; to make room for the new
or ah,al ;Store new value
dec bx ;Count the dot
jnz @F ;Go if more of same to come
inc si ;Else point to next cell
mov bx,ldot_rpt ; and reload count
cmp si,lend_col ;End of column?
jne @F ;No -- go
inc lendcol_flag ;Else set flag
@@: loop CGA_disp_3 ;Get all 4 dots
mov cx,lrow_rpt ;Rows to repeat
push di ;Save video ptr
CGA_disp_4: mov es:[di],ah ;Store this value
add di,2000h ;Move to next line
cmp di,4000h ;Time to move back?
jb @F ;No -- go
sub di,4000h-80 ;Yes -- back to top half
@@: loop CGA_disp_4 ;Display it all
pop di ;Recover video ptr
inc di ;Move to next position
test lendcol_flag,-1 ;End of this row?
jz CGA_disp_2 ;No -- do some more
CGA_disp_5: pop di ;Get start of line
mov cx,lrow_rpt ;Get repeat count
CGA_disp_6: add di,2000h ;Move to next row
cmp di,4000h ;Was at bottom?
jb @F ;No -- go
sub di,4000h-80 ;Else move back up
@@: loop CGA_disp_6 ;Repeat as needed
pop si ;Get line position
add si,lbufcols ;Move to next
dec lrows ;Count one row
jnz CGA_disp_1 ;Do next row
ret
CGA_disp_buf endp
;************
; EGA_disp_buf -- Displays the universe using EGA 16-color, 640x350 graphics
;************
EGA_disp_buf proc near uses di si ds es
local lrow_rpt, ldot_rpt, lbufcols
local lcols, lrows, lend_col, lendcol_flag
mov bx,border_on ;Get border flag
mov ax,row_repeat ;Copy values so we
mov lrow_rpt,ax ; can get to them
mov ax,dot_repeat ; through SS instead
mov ldot_rpt,ax ; of DS
mov ax,bufcols
mov lbufcols,ax
mov ax,cols
mov lcols,ax
mov ax,rows
mov lrows,ax
mov dx,3ceh ;EGA/VGA Graphics port
mov ax,0205h ;Select write mode 2
out dx,ax
mov es,[vidseg]
sub di,di ;ES:DI ==> video buffer
lds si,bufaddr ;DS:SI ==> universe buffer
add si,lbufcols ;Skip top border
add si,bx ; and left border
EGA_disp_1: push si ;Save buffer pointers
push di
mov ax,si ;Get start column
add ax,lcols ;AX = last col + 1
mov lend_col,ax ;Save the value
sub ax,ax ;AX = 0
mov lendcol_flag,ax ;Turn the flag off
mov bx,ldot_rpt ;BX = times to repeat a dot
mov ah,80h ;Bit mask
mov al,08h ;Bit mask register
EGA_disp_2: mov bh,[si] ;Get a value
out dx,ax ;Select 1-pixel mask
mov cl,es:[di] ;Set EGA latches
mov es:[di],bh ;Set the dot
dec bl ;Count one dot
jnz @F ;Go if more of the same
inc si ;Else move to next place
mov bx,ldot_rpt ; and pick up counter
cmp si,lend_col ;At end of the row?
jne @F ;No -- go
inc lendcol_flag ;Yes -- set flag
@@: clc ;Clear carry flag
rcr ah,1 ;Move bit mask right
jnc EGA_disp_2 ;Repeat until carry set
mov cx,lrow_rpt ;Get row repeat count
dec cx ;Reduce by 1
jcxz EGA_disp_3 ;Go if no repeat
sub ah,ah ;Bit mask = 0
out dx,ax ;Set bit mask
mov bh,es:[di] ;Set latches
push di ;Save video pointer
@@: add di,80 ;Move to next line
mov es:[di],bh ;Copy byte
loop @B ;For all repeats
pop di ;Get back original
EGA_disp_3: inc di ;Move to next position
mov ah,80h ;Set new bit mask
test lendcol_flag,-1 ;Done with this row?
jz EGA_disp_2 ;No -- do some more dots
pop di ;Else pop original
pop si ; pointers
dec lrows ;Count one row
jz EGA_disp_4 ;Go if done
add si,lbufcols ;Move to next buffer row
mov cx,lrow_rpt ;Get row repeat count
@@: add di,80 ;Move down required rows
loop @B
jmp EGA_disp_1 ;Loop back for another row
EGA_disp_4: mov ax,0ff08h ;Put bit mask back to normal
out dx,ax
mov ax,00005h ;Restore write mode 0
out dx,ax
ret
EGA_disp_buf endp
; Use the following segment definition for Micrsoft languages:
; Quick Basic, Quick C, MSC
ca_buf segment
; Use the following segment definition for Turbo C. The line will work
; but cause a Link warning if used with Microsoft languages.
;ca_buf segment para public 'CODE'
dw 8000h dup (?)
ca_buf ends
end